﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using Moq;
using Castle.MicroKernel;
using Castle.MicroKernel.SubSystems.Naming;
using Castle.Core;

namespace MoqContrib.AutoMock.Castle
{
    /// <summary>
    /// Provides container
    /// </summary>
    public class AutoMockHelper : MoqContrib.AutoMock.AutoMockHelper
    {
        /// <summary>
        /// This is required to be set before 
        /// </summary>
        public IWindsorContainer Container { get; set; }

        /// <summary>
        /// Called when the parent helper needs to register a mock
        /// </summary>
        /// <param name="type"></param>
        /// <param name="instance"></param>
        protected override void RegisterInstance(Type type, object instance)
        {
            // TODO: Write tests for this method
            Container.Register(Component.For(type).Instance(instance));
        }

		/// <summary>
		/// Create an instance of T with all it's dependancies mocked.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		public override T CreateTestSubject<T>()
		{
			if (!HasComponent<T>(Container))
				Container.Register(Component.For<T>().LifeStyle.Is(LifestyleType.Transient));
			return Container.Resolve<T>();
		}

		private static bool HasComponent<T>(IWindsorContainer container)
			where T : class
		{
			bool isClass = typeof(T).IsClass;
			bool hasComponent = container.Kernel.HasComponent(typeof(T));
			if (isClass && hasComponent)
				return true;
			else
			{
				foreach (var @interface in typeof(T).GetInterfaces())
				{
					foreach (var component in container.ResolveAll(@interface))
					{
						if (component is T)
						{
							RegisterTypeAsAdditionalInterface(container, @interface, typeof(T));
							return true;
						}
					}
				}
			}
			return false;
		}

		private static void RegisterTypeAsAdditionalInterface(IWindsorContainer container, Type @interface, Type type)
		{
			var handler = container.Kernel.GetHandler(@interface);
			var kernel = container.Kernel as IKernelInternal;
			kernel.RegisterHandlerForwarding(type, handler.ComponentModel.Name);
		}

		private class CustomRegistration : IRegistration
		{

			#region IRegistration Members

			public void Register(IKernel kernel)
			{
			}

			#endregion
		}

        /// <summary>
        /// Called when the parent helper needs to register a mock
        /// </summary>
        /// <param name="type"></param>
        /// <param name="key"></param>
        /// <param name="instance"></param>
        protected override void RegisterInstance(Type type, string key, object instance)
        {
            // TODO: write tests for this method
            Container.Register(Component.For(type).Instance(instance).Named(key));
        }

        /// <summary>
        /// Register a single instance for all of these services.
        /// </summary>
        /// <param name="services"></param>
        /// <param name="instance"></param>
        protected override void RegisterInstance(Type[] services, object instance)
        {
            Container.Register(
                Component.For(services).Instance(instance)
            );
        }
    }
}
